﻿/**
 * Author: HAO, Wei
 * Date: 2019/01/03 Initialize this class.
 * 
 * */
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace WindGoes6.Data
{
	/// <summary>
	/// 基本的CSV结构，符合以下几点特征：
	/// - 以逗号为分隔符 (也可以为分号或制表符，可以通过seperator指定。）
	/// - 以\n或\r\n为行分隔符
	/// - 开头是不留空，以行为单位。
	/// - 不含列名，如果需要带列名的，请使用HeadedCSV
	/// - 数据不跨行且无空行。
	/// - 列为空也要表达其存在。
	/// - 如果存在分隔符，则使用一对半角引号将整个单元格的值包起来。
	/// - 如果在值中存在半角引号，则使用2个半角引号表示
	/// - 文件读写时引号，逗号操作规则互逆。
	/// - 内码格式不限，可为 ASCII、Unicode 或者其他。
	/// - 不支持特殊字符。
	/// </summary>
	public class MyCSV
	{
		/// <summary>
		/// 分隔符，默认为半角的逗号。
		/// </summary>
		public string Seperator { get; set; } = ",";

		/// <summary>
		/// 文件的编码。
		/// </summary>
		public Encoding Encoding { get; set; } = Encoding.Default;

		/// <summary>
		/// 所有的数据都保存在些数组中。
		/// </summary>
		private List<string[]> Lines { get; set; } = new List<string[]>();

		/// <summary>
		/// CSV是一种通用的使用逗号隔开的二维表的结构文件。
		/// </summary>
		public MyCSV() { }

		/// <summary>
		/// 通过指定的CSV文件进行加载。
		/// </summary>
		/// <param name="filepath"></param>
		public MyCSV(string filepath) { Read(filepath); }

		public MyCSV(string filepath, Encoding encoding)
		{
			Encoding = encoding;
			Read(filepath);
		}


		/// <summary>
		/// 返回总行数。
		/// </summary>
		/// <returns></returns>
		public int RowCount { get { return Lines.Count; } }

		/// <summary>
		/// 返回总列数。
		/// </summary>
		public int ColumnCount { get { return Lines != null && Lines.Count > 0 ? Lines[0].Length : 0; } }

		/// <summary>
		/// 返回指定行列的值。
		/// </summary>
		/// <param name="rowid"></param>
		/// <param name="columnid"></param>
		/// <returns></returns>
		public string GetData(int rowid, int columnid)
		{
			return IsValid(rowid, columnid) ? Lines[rowid][columnid] : null;
		}

		/// <summary>
		/// 读写CSV指定单元格。
		/// </summary>
		/// <param name="row">指定的行。</param>
		/// <param name="column">指定的列。</param>
		/// <returns></returns>
		public string this[int row, int column]
		{
			get { return GetData(row, column); }
			set { SetData(row, column, value); }
		}

		/// <summary>
		/// 判断指定行列的单元格是否为有效范围内的。
		/// </summary>
		/// <param name="rowid">指定的行编号。</param>
		/// <param name="columnid">指定的列编号。</param>
		/// <returns></returns>
		public bool IsValid(int rowid, int columnid) { return rowid >= 0 && rowid < Lines.Count && columnid >= 0 && columnid < Lines[0].Length; }

		/// <summary>
		/// 为指定编号的行列的单元格赋值。
		/// </summary>
		/// <param name="row"></param>
		/// <param name="column"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		internal bool SetData(int row, int column, string value)
		{
			bool valid = IsValid(row, column);
			if (valid)
				Lines[row][column] = value;
			return valid;
		}

		/// <summary>
		/// 读取CSV数据文件, 目前的版本不支持带有分隔符的内容。
		/// </summary>
		/// <param name="csvfile">待加载的CSV文件。</param>
		public void Read(string csvfile)
		{
			string filepath = Path.GetFullPath(csvfile);
			if (!File.Exists(filepath))
				throw new FileNotFoundException(filepath + " does not exist.");

			Lines = new List<string[]>();
			char c17 = (char)17;
			char c18 = (char)18;


			// 读取所有的非空行
			foreach (var line in File.ReadAllLines(filepath, Encoding))
			{

				StringBuilder sb = new StringBuilder();

				// 1）所有双半角引号替换成 (char)17
				sb.Append(line.Replace("\"\"", c17 + ""));

				// 2）所有在引号中的分隔符替换为 (char)18
				bool isValue = false;
				for (int i = 0; i < sb.Length; i++)
				{
					isValue = sb[i] == '\"' ? !isValue : isValue;
					if (sb[i] == Seperator[0] && isValue)
						sb[i] = c18;
				}

				// 3) 根据分隔符进行拆分
				string[] cells = sb.ToString().Split(Seperator[0]);

				// 4）还原特殊字符1和特殊字符2为引号和逗号
				for (int i = 0; i < cells.Length; i++) 
					cells[i] = cells[i].Replace("\"", "").Replace(c17, '\"').Replace(c18, Seperator[0]);

				Lines.Add(cells);
			}


		}

		/// <summary>
		/// 将数据进行保存，默认使用编号进行保存。 
		/// </summary>
		/// <param name="filepath">需要保存的路径。</param>
		public void Save(string filepath)
		{
			StringBuilder sb = new StringBuilder();
			foreach (string[] line in Lines)
			{
				for (int i = 0; i < line.Length; i++)
				{
					// 所有的双引号进行X2转义即  " -> ""
					line[i] = line[i].Replace("\"", "\"\"");

					// 如果有分隔符或引号，则左右加上引号后输出。
					if (line[i].Contains('\"') || line[i].Contains(Seperator))
						sb.Append($"\"{line[i]}\"");
					else
						sb.Append(line[i]);

					//除了最后一个单元格，其他都加上分隔符。
					if (i != line.Length - 1)
						sb.Append(Seperator);
				}

				sb.Append("\r\n");
			}

			File.WriteAllText(filepath, sb.ToString(), Encoding);
		}

		public override string ToString()
		{
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < Lines.Count; i++)
			{
				sb.AppendLine(string.Join("\t\t", Lines[i]));
			}
			return sb.ToString();
		}

	}

}
